// Copyright (C) 2008 Taylor L. Riche <riche@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//

package appcomp.pathfinder;

import static org.junit.Assert.*;

import java.net.URI;
import java.util.ArrayList;

import org.junit.Test;

import utility.Pair;
import appcomp.entities.*;

public class PathfinderTest {

	@Test
	public void testFindPaths() {
		Type testType = Type.create("testType", URI.create("test"), "test");
		Port op1in1 = Port.create("op1in1", "handler1", Port.Direction.IN, testType);
		Port op1out1 = Port.create("op1out1", null, Port.Direction.OUT, testType);
		ArrayList<Port> portList = new ArrayList<Port>();
		portList.add(op1in1);
		portList.add(op1out1);
		Operator op1 = RequestGenerator.create("op1", portList, URI.create("fake"), "FakeType");
		op1.setMasterRequestType(testType);
		Port op2in1 = Port.create("op2in1", "handler2", Port.Direction.IN, testType);
		Port op2out1 = Port.create("op2out1", null, Port.Direction.OUT, testType);
		portList = new ArrayList<Port>();
		portList.add(op2in1);
		portList.add(op2out1);
		Operator op2 = Operator.create("op2", null, portList);
		Connector con1 = Connector.create(new Pair<String, String>("op1", "op1out1"), new Pair<String, String>("op2", "op2in1"));
		con1.setIn(op1);
		con1.setOut(op2);
		op1.registerConnection("op1out1", con1);
		Port op3in1 = Port.create("op3in1", "handler3", Port.Direction.IN, testType);
		Port op3out1 = Port.create("op3out1", null, Port.Direction.OUT, testType);
		Type offType = Type.create("offType", URI.create("off"), "off");
		Port op3out2 = Port.create("op3out2", null, Port.Direction.OUT, offType);
		Port op3out3 = Port.create("op3out3", null, Port.Direction.OUT, testType);
		portList = new ArrayList<Port>();
		portList.add(op3in1);
		portList.add(op3out1);
		portList.add(op3out2);
		portList.add(op3out3);
		Operator op3 = Operator.create("op3", null, portList);
		Connector con2 = Connector.create(new Pair<String, String>("op2", "op2out1"), new Pair<String, String>("op3", "op3in1"));
		con2.setIn(op2);
		con2.setOut(op3);
		op2.registerConnection("op2out1", con2);
		Pathfinder pf = new Pathfinder();	
		if (pf.findPaths(op1) != 0) {
			fail("Found nonexistant paths!");
		}
		Port op4in1 = Port.create("op4in1", "handler4", Port.Direction.IN, testType);
		Port op4out1 = Port.create("op4out1", null, Port.Direction.OUT, testType);
		portList = new ArrayList<Port>();
		portList.add(op4in1);
		portList.add(op4out1);
		Operator op4 = RequestGenerator.create("op4", portList, URI.create("fake"), "FakeType");
		Connector con3 = Connector.create(new Pair<String, String>("op3", "op3out1"), new Pair<String, String>("op4", "op4in1"));
		con3.setIn(op3);
		con3.setOut(op4);
		op3.registerConnection("op3out1", con3);
		pf = new Pathfinder();
		System.out.println(pf.findPaths(op1));
		if (pf.getNumPaths() > 1) {
			fail("Too many paths!");
		}
		else if (pf.getNumPaths() == 0) {
			fail("Didn't find paths!");
		}
		portList = new ArrayList<Port>();
		Port op5in1 = Port.create("op5in1", "handler1", Port.Direction.IN, offType);
		portList.add(op5in1);
		Operator op5 = Operator.create("op5", null, portList);
		Connector con4 = Connector.create(new Pair<String, String>("op3", "op3out2"), new Pair<String, String>("op5", "op5in1"));
		con4.setIn(op3);
		con4.setOut(op5);
		op3.registerConnection("op3out2", con4);
		pf = new Pathfinder();
		pf.findPaths(op1);
		if (pf.getNumPaths() > 1) {
			fail("Didn't prune off type!");
		}
		else if (pf.getNumPaths() == 0) {
			fail("Didn't find paths!");
		}
		pf.printPaths();
		// test multiple legitimate paths
		portList = new ArrayList<Port>();
		Port op6in1 = Port.create("op6in1", "handler1", Port.Direction.IN, testType);
		Port op6out1 = Port.create("op6out1", null, Port.Direction.OUT, testType);
		portList.add(op6in1);
		portList.add(op6out1);
		Operator op6 = Operator.create("op6", null, portList);
		Connector con5 = Connector.create(new Pair<String, String>("op3", "op3out3"), new Pair<String, String>("op6", "op6in1"));
		con5.setIn(op3);
		con5.setOut(op6);
		op3.registerConnection("op3out3", con5);
		Connector con6 = Connector.create(new Pair<String, String>("op6", "op6out1"), new Pair<String, String>("op4", "op4in1"));
		con6.setIn(op6);
		con6.setOut(op4);
		op6.registerConnection("op6out1", con6);
		pf = new Pathfinder();
		pf.findPaths(op1);
		if (pf.getNumPaths() < 2) {
			fail("Didn't find enough paths: " + pf.getNumPaths());
		}
		else if (pf.getNumPaths() > 2) {
			fail("Found too many paths.");
		}
		pf.printPaths();
		
	}

}
